﻿using System;
using Firefly.Framework.Components.Cameras;
using Firefly.Framework.ContentManagement;
using Firefly.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Firefly.Framework.Components.Sky
{
    public class Moon : DrawableComponent, IHasCamera
    {
        private VertexPositionTexture[] _quadVertexBuffer;
        private QuadRenderer _quadRenderer;
        private TexturedShader _shader;
        private string _moonAssetName;
        private string _glowAssetName;
        private Texture2D _moonTexture;
        private Texture2D _glowTexture;

        public float Theta { get; set; }
        public float Phi { get; set; }
        public Vector3 SunlightDirection { get; set; }
        public float Alpha
        {
            get { return _shader.Alpha; }
            set { _shader.Alpha = value; }
        }

        public Moon(Game game, string moonAssetName, string glowAssetName, ICamera camera)
            : base(game)
        {
            _moonAssetName = moonAssetName;
            _glowAssetName = glowAssetName;
            Camera = camera;
        }

        private void GenerateQuad()
        {
            _quadVertexBuffer = new VertexPositionTexture[]
                {
                    new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1)),
                    new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1)),
                    new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0, 0)),
                    new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0))
                };
        }

        private Matrix CreateRotationX(int multiplier)
        {
            return Matrix.CreateRotationX((Theta + ((float)Math.PI / 2.0f))) *
                Matrix.CreateRotationY(-Phi + ((float)Math.PI / 2.0f)) *
                Matrix.CreateTranslation(SunlightDirection.X * multiplier, SunlightDirection.Y * multiplier, SunlightDirection.Z * multiplier) *
                Matrix.CreateTranslation(Camera.Position.X, Camera.Position.Y, Camera.Position.Z);
        }

        #region IHasContent Members

        public override void LoadContent()
        {
            _moonTexture = ContentService.Instance.Load<Texture2D>(_moonAssetName);
            _glowTexture = ContentService.Instance.Load<Texture2D>(_glowAssetName);
            GenerateQuad();
            _quadRenderer = new QuadRenderer(Game, _quadVertexBuffer) { FullScreen = false };
            _quadRenderer.LoadContent();
            _shader = new TexturedShader(this);
            _shader.QuadRenderer = _quadRenderer;
            _shader.LoadContent();
        }

        public override void UnloadContent()
        {
            if (_quadRenderer != null)
            {
                _quadRenderer.Dispose();
                _quadRenderer = null;
            }

            ContentService.Instance.Release(_moonAssetName);
            ContentService.Instance.Release(_glowAssetName);
            _shader.UnloadContent();
        }

        #endregion

        #region IDrawable Members

        public override void Draw(GameTime gameTime)
        {
            if (Visible)
            {
                GraphicsService.Instance.RenderState.AlphaBlendEnable = true;
                GraphicsService.Instance.RenderState.SourceBlend = Blend.SourceAlpha;
                GraphicsService.Instance.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
                _shader.World = CreateRotationX(5);
                _shader.View = Camera.View;
                _shader.Projection = Camera.Projection;
                _shader.Texture = _glowTexture;
                _shader.Draw(gameTime);
                _shader.World = CreateRotationX(15);
                _shader.Texture = _moonTexture;
                _shader.Draw(gameTime);
                GraphicsService.Instance.RenderState.AlphaBlendEnable = false;
            }
        }

        #endregion

        #region IHasCamera Members

        public ICamera Camera { get; set; }

        #endregion

        #region IDisposable Members

        ~Moon()
        {
            Dispose(false);
        }

        #endregion
    }
}
